package main

/**
在上一节课中我留了一个作业，也就是让你自己练习使用 sync.Map，相信你已经做出来了。现在我为你讲解 sync.Map 的方法。
Store：存储一对 key-value 值。
Load：根据 key 获取对应的 value 值，并且可以判断 key 是否存在。
LoadOrStore：如果 key 对应的 value 存在，则返回该 value；如果不存在，存储相应的 value。
Delete：删除一个 key-value 键值对。
Range：循环迭代 sync.Map，效果与 for range 一样。
相信有了这些方法的介绍，你对 sync.Map 会有更深入的理解。下面开始今天的课程：如何通过 Context 更好地控制并发。
*/
//
//func main() {
//	var smap sync.Map
//	var wg = sync.WaitGroup{}
//	var cond = sync.Cond{L: &sync.RWMutex{}}
//	wg.Add(2)
//	//smap.Store("name", "小明")
//
//	//go func(s *sync.Map) {
//	//	defer wg.Done()
//	//	name, _ := s.Load("name")
//	//	fmt.Println("从map中获取值", name)
//	//}(&smap)
//
//	go func(s *sync.Map) {
//		defer wg.Done()
//		cond.L.Lock()
//		defer cond.L.Unlock()
//		done, ok := s.Load("done")
//		if ok {
//			fmt.Println("work协程 wait已经done了,", done)
//		} else {
//			fmt.Println("等待work协程执行完毕")
//			cond.Wait()
//		}
//		s.Store("age", 18)
//		fmt.Println("在map中存储值--", 18)
//		cond.Broadcast() // 在调用 Signal 或者 Broadcast 之前，要确保目标协程处于 Wait 阻塞状态，不然会出现死锁问题。
//		// 就是说一定要保证下面协程的wait语句先执行
//		fmt.Println("唤醒其他协程")
//	}(&smap)
//
//	go func(s *sync.Map) {
//		time.Sleep(time.Second)
//		defer wg.Done()
//		cond.L.Lock()
//		defer cond.L.Unlock()
//		//for true{
//		//	if age, ok := s.Load("age"); ok {
//		//		fmt.Println("从map中获取值",age)
//		//		break
//		//	}else {
//		//		fmt.Println("开始等待")
//		//		cond.Wait()
//		//		fmt.Println("被唤醒")
//		//	}
//		//}
//
//		s.Store("done", "done")
//		fmt.Println("work协程开始准备获取age")
//		age, ok := s.Load("age")
//		fmt.Println("ok:", ok)
//		if ok {
//			fmt.Println("从map中获取值", age)
//		} else {
//			fmt.Println("开始等待")
//			cond.Wait()
//			fmt.Println("被唤醒")
//		}
//	}(&smap)
//
//	wg.Wait()
//}
